﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Activities;
using Microsoft.TeamFoundation.Build.Client;
using System.ComponentModel;
using Microsoft.TeamFoundation.Build.Workflow;
using Microsoft.TeamFoundation.Build.Workflow.Activities;
using System.Xml;
using System.Threading;

namespace TFSBuildActivitiesLibrary
{
    [BuildActivity(HostEnvironmentOption.All)]
    public sealed class QueueAsyncBuild : AsyncCodeActivity<IBuildDetail>
    {
        /// <summary>
        /// Sets the parent build detail object.
        /// </summary>
        /// <value>
        /// The build detail.
        /// </value>
        [RequiredArgument]
        public InArgument<IBuildDetail> BuildDetail { get; set; }
        /// <summary>
        /// Sets the build name for a child build.
        /// </summary>
        /// <value>
        /// The name of the build.
        /// </value>
        [RequiredArgument]
        public InArgument<string> BuildName { get; set; }
        /// <summary>
        /// Sets the child build quality.
        /// </summary>
        /// <value>
        /// The build quality.
        /// </value>
        [DefaultValue("Undefined")]
        public InArgument<string> BuildQuality { get; set; }
        /// <summary>
        /// Sets the child build input arguments.
        /// </summary>
        /// <value>
        /// The build input arguments.
        /// </value>
        public InArgument<IDictionary<string, object>> InputArguments { get; set; }

        private IQueuedBuild queuedBuild;

        protected override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
        {
            queuedBuild = ExecuteBuild(context);

            if (queuedBuild == null)
            {
                Utilities.TrackMessage(context, "Error, IQueuedBuild is null");
                Cancel(context);
            }

            var executeDelegate = new Action(FakeWork);
            context.UserState = executeDelegate;
            return executeDelegate.BeginInvoke(callback, state);
        }

        protected override IBuildDetail EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
        {
            var executeDelegate = (Action)context.UserState;
            executeDelegate.EndInvoke(result);

            WaitForBuildCompletion(context);

            return queuedBuild.Build;
        }

        protected override void Cancel(AsyncCodeActivityContext context)
        {
            // Implement any cleanup as a result of the asynchronous work
            // being canceled, and then call MarkCanceled.
            if (context.IsCancellationRequested)
            {
                context.MarkCanceled();
            }
        }

        //http: //stackoverflow.com/questions/5313543/windows-workflow-4-when-are-tracking-records-emitted
        private void FakeWork()
        {
            // do nothing
            // This allows the CustomTrackingRecord to be handled by the WorkFlowTracker 
            // so that we can identify the start of the activity.
            // The real work is done synchronously in the EndExecute method.
        }

        private IQueuedBuild ExecuteBuild(AsyncCodeActivityContext context)
        {
            IBuildDetail buildDetail = context.GetValue(this.BuildDetail);
            string buildDefinitionName = context.GetValue(this.BuildName);
            IDictionary<string, object> dictInputArguments = context.GetValue(this.InputArguments);

            IQueuedBuild qbuild = Utilities.BeginExecute(context, buildDetail, buildDefinitionName, dictInputArguments);

            return qbuild;
        }

        private IBuildDetail WaitForBuildCompletion(AsyncCodeActivityContext context)
        {
            string strBuildQuality = context.GetValue(this.BuildQuality);

            if (queuedBuild == null) return null;

            Utilities.EndExecute(context, queuedBuild, strBuildQuality);

            return queuedBuild.Build;
        }
    }
}
